package ru.zombator.taskman.server.query;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import ru.zombator.taskman.core.domain.IPerson;
import ru.zombator.taskman.core.query.IPacket;
import ru.zombator.taskman.core.query.IResponderSvc;
import ru.zombator.taskman.core.query.ITypedPacket;
import ru.zombator.taskman.core.query.LogHandler;
import ru.zombator.taskman.core.query.TypedPacket;
import ru.zombator.taskman.core.query.payload.ErrorResponse;
import ru.zombator.taskman.core.query.payload.WhoAmIRequest;
import ru.zombator.taskman.core.query.payload.WhoAmIResponse;

/**
 * Базовая реализация внутреннего интерфейса сервера.
 * <p>
 * Реализовано только добавление слушателей лога
 * 
 * @author nvamelichev
 * 
 */
public class BaseServer implements IResponderSvc {
	protected List<LogHandler> handlers = new ArrayList<LogHandler>();

	@Override
	public void addLogHandler(LogHandler handler) {
		handlers.add(handler);
	}

	@Override
	public void removeLogHandler(LogHandler handler) {
		handlers.remove(handler);
	}

	@Override
	public void dispose() {
	}

	/**
	 * Получает ответ на запрос
	 * 
	 * @param request
	 * @param clientIpAddress
	 * @param logHandlers
	 * @return
	 * @throws RemoteException
	 */
	protected IPacket getResponse(IPacket request, String clientIpAddress)
			throws RemoteException {
		try {
			LocalResponder whoAmIResponder = ResponderFactory
					.newResponderForWhoAmI(clientIpAddress);
			boolean servingWhoAmIRequest = new TypedPacket(request).asObject() instanceof WhoAmIRequest;
			if (servingWhoAmIRequest)
				addHandlersToResp(whoAmIResponder);
			IPacket respToWhoAmI = whoAmIResponder.getResponse(servingWhoAmIRequest ? request:
				new TypedPacket(new WhoAmIRequest()).asUntyped());
			ITypedPacket whoAmIPkt = new TypedPacket(respToWhoAmI);
			if (servingWhoAmIRequest)
				return respToWhoAmI;

			if (whoAmIPkt.asObject() instanceof ErrorResponse) {
				throw new RemoteException(
						((ErrorResponse) whoAmIPkt.asObject()).getMessage());
			}
			WhoAmIResponse whoResp = (WhoAmIResponse) whoAmIPkt.asObject();
			IPerson caller = whoResp.getWho();
			LocalResponder responder = ResponderFactory.newResponder(caller);
			addHandlersToResp(responder);
			return responder.getResponse(request);
		} catch (Exception e) {
			throw new RemoteException("", e);
		}
	}

	private void addHandlersToResp(LocalResponder actualResponder) {
		for (LogHandler handler : handlers) {
			actualResponder.addLogHandler(handler);
		}
	}
}
